﻿using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace AgLux
{
    /// <summary>
    /// //
    /// </summary>

    public class Media : Component
    {
        protected MediaElement _media;
        protected Canvas _play, _pause, _stop;

        protected Canvas _volume, _volumePlus, _volumeMinus, _transButton;
        protected MediaElement _volumeSound;
        protected List<Path> _volumeSteps;
        protected List<SolidColorBrush> _volumeColors;

        protected Canvas _scrub;
        protected Rectangle _scrubBar, _scrubRuler;
        protected Ellipse _scrubStop, _scrubber;
        protected TextBlock _scrubTime,_transText;

        protected Storyboard _volumePressed, _millisecond;

        protected double _milliseconds;
        protected bool _isScrubbing;
        protected string _transcript;

        /// <summary>
        /// //
        /// </summary>

        /// <param name="source">
        /// //
        /// </param>

        protected Media(string source, string transcript)
            : base()
        {
            _media = (MediaElement)_resource.FindName("media");

            _transButton = (Canvas)_resource.FindName("button");
            _transText = (TextBlock)_resource.FindName("buttonText");

            _play = (Canvas)_resource.FindName("play");
            _pause = (Canvas)_resource.FindName("pause");
            _stop = (Canvas)_resource.FindName("stop");

            _volume = (Canvas)_resource.FindName("volume");
            _volumePlus = (Canvas)_resource.FindName("volumePlus");
            _volumeMinus = (Canvas)_resource.FindName("volumeMinus");
            _volumeSound = (MediaElement)_resource.FindName("volumeSound");

            _volumeSteps = new List<Path>();
            _volumeSteps.Add((Path)_resource.FindName("volume1"));
            _volumeSteps.Add((Path)_resource.FindName("volume2"));
            _volumeSteps.Add((Path)_resource.FindName("volume3"));
            _volumeSteps.Add((Path)_resource.FindName("volume4"));
            _volumeSteps.Add((Path)_resource.FindName("volume5"));
            _volumeSteps.Add((Path)_resource.FindName("volume6"));
            _volumeSteps.Add((Path)_resource.FindName("volume7"));
            _volumeSteps.Add((Path)_resource.FindName("volume8"));
            _volumeSteps.Add((Path)_resource.FindName("volume9"));
            _volumeSteps.Add((Path)_resource.FindName("volume10"));

            _volumeColors = new List<SolidColorBrush>();
            _volumeColors.Add(new SolidColorBrush(Color.FromRgb(255, 234, 130)));
            _volumeColors.Add(new SolidColorBrush(Color.FromRgb(254, 238, 0)));
            _volumeColors.Add(new SolidColorBrush(Color.FromRgb(255, 255, 0)));
            _volumeColors.Add(new SolidColorBrush(Color.FromRgb(253, 184, 19)));
            _volumeColors.Add(new SolidColorBrush(Color.FromRgb(247, 147, 29)));
            _volumeColors.Add(new SolidColorBrush(Color.FromRgb(244, 121, 50)));
            _volumeColors.Add(new SolidColorBrush(Color.FromRgb(243, 111, 49)));
            _volumeColors.Add(new SolidColorBrush(Color.FromRgb(240, 78, 69)));
            _volumeColors.Add(new SolidColorBrush(Color.FromRgb(218, 31, 61)));
            _volumeColors.Add(new SolidColorBrush(Color.FromRgb(191, 36, 85)));

            _scrub = (Canvas)_resource.FindName("scrub");
            _scrubBar = (Rectangle)_resource.FindName("scrubBar");
            _scrubRuler = (Rectangle)_resource.FindName("scrubRuler");
            _scrubStop = (Ellipse)_resource.FindName("scrubStop");
            _scrubber = (Ellipse)_resource.FindName("scrubber");
            _scrubTime = (TextBlock)_resource.FindName("scrubTime");

            _volumePressed = (Storyboard)_resource.FindName("volumePressed");
            _millisecond = (Storyboard)_resource.FindName("millisecond");

            _milliseconds = 0;
            _isScrubbing = false;

            _media.Source = new Uri(source, UriKind.RelativeOrAbsolute);
            _media.Visibility = Visibility.Visible;
            _media.MediaOpened += new EventHandler(GetMilliseconds);
            _media.MediaEnded += new EventHandler(Stop);
            _media.CurrentStateChanged += new EventHandler(CheckState);

            _play.Visibility = _stop.Visibility = _volumePlus.Visibility = _volumeMinus.Visibility = Visibility.Visible;

            _play.MouseLeftButtonDown += new MouseEventHandler(Play);
            _pause.MouseLeftButtonDown += new MouseEventHandler(Pause);
            _stop.MouseLeftButtonDown += new MouseEventHandler(Stop);

            _volume.Visibility = Visibility.Visible;
            _volumePlus.MouseLeftButtonDown += new MouseEventHandler(VolumePlus);
            _volumeMinus.MouseLeftButtonDown += new MouseEventHandler(VolumeMinus);

            _scrub.Visibility = Visibility.Visible;
            _scrub.MouseMove += new MouseEventHandler(CheckScrub);
            _scrub.MouseLeftButtonDown += new MouseEventHandler(ActivateScrubbing);
            _scrub.MouseLeftButtonUp += new MouseEventHandler(InactivateScrubbing);
            _scrub.MouseLeave += new EventHandler(InactivateScrubbing);

            _millisecond.Completed += new EventHandler(MoveScrubber);

            _transcript = transcript;

            if (_transcript != "")
            {
                _transText.Text = "Transcript";
                _transButton.Visibility = Visibility.Visible;
                _transButton.MouseLeftButtonUp += new MouseEventHandler(_transButton_MouseLeftButtonUp);
            }
        }

        void _transButton_MouseLeftButtonUp(object sender, MouseEventArgs e)
        {
            System.Windows.Browser.HtmlPage.Navigate(_transcript, "myTarget");
        }

        /// <summary>
        /// //
        /// </summary>

        protected virtual void SetVolume()
        {
            if (BrowserHost.IsFullScreen)
            {
                _volume.SetValue(Canvas.TopProperty, ScreenHeight - _volume.Height);
            }

            else
            {
                _volume.SetValue(Canvas.TopProperty, ScreenHeight + _caption.Height + 10);
            }
        }

        /// <summary>
        /// //
        /// </summary>

        /// <param name="width">
        /// //
        /// </param>

        protected virtual void SetScrub(double width)
        {
            _scrub.Width = width;
            _scrub.SetValue(Canvas.LeftProperty, _volume.Width + 10);
            _scrub.SetValue(Canvas.TopProperty, ScreenHeight + _caption.Height + _volume.Height / 2 - _scrub.Height / 2 + 10);
            _scrubBar.Width = width - _scrubTime.ActualWidth - 10;
            _scrubRuler.SetValue(Canvas.LeftProperty, 17.5);
            _scrubRuler.Width = width - _scrubTime.ActualWidth - 45;
            _scrubStop.SetValue(Canvas.LeftProperty, width - _scrubTime.ActualWidth - 20);
            _scrubber.SetValue(Canvas.LeftProperty, (Convert.ToDouble(_media.Position.TotalMilliseconds) / _milliseconds * _scrubRuler.Width) + 10);
            _scrubTime.SetValue(Canvas.LeftProperty, width - _scrubTime.ActualWidth);
            _scrubTime.SetValue(Canvas.TopProperty, _scrub.Height / 2 - _scrubTime.ActualHeight / 2);

            if (BrowserHost.IsFullScreen)
            {
                _scrub.SetValue(Canvas.TopProperty, ScreenHeight - _volume.Height / 2 - _scrub.Height / 2);
            }
        }

        /// <summary>
        /// //
        /// </summary>

        /// <param name="sender">
        /// //
        /// </param>

        /// <param name="args">
        /// //
        /// </param>

        protected virtual void GetMilliseconds(object sender, EventArgs args)
        {
            _milliseconds = Convert.ToDouble(_media.NaturalDuration.TimeSpan.TotalMilliseconds);
            _scrubTime.Text = "0:00 / " + _media.NaturalDuration.TimeSpan.Minutes + ":" + _media.NaturalDuration.TimeSpan.Seconds;
        }

        /// <summary>
        /// //
        /// </summary>

        /// <param name="sender">
        /// //
        /// </param>

        /// <param name="args">
        /// //
        /// </param>
        
        protected virtual void Play(object sender, MouseEventArgs args)
        {
            _media.Play();
            _millisecond.Begin();

            _play.Visibility = Visibility.Collapsed;
            _pause.Visibility = Visibility.Visible;
        }

        /// <summary>
        /// //
        /// </summary>

        /// <param name="sender">
        /// //
        /// </param>

        /// <param name="args">
        /// //
        /// </param>

        protected virtual void Pause(object sender, MouseEventArgs args)
        {
            _media.Pause();
            _millisecond.Stop();

            _pause.Visibility = Visibility.Collapsed;
            _play.Visibility = Visibility.Visible;
        }

        /// <summary>
        /// //
        /// </summary>

        /// <param name="sender">
        /// //
        /// </param>

        /// <param name="args">
        /// //
        /// </param>

        protected virtual void Stop(object sender, EventArgs args)
        {
            _media.Stop();

            CheckState(sender, args);
        }

        /// <summary>
        /// //
        /// </summary>

        /// <param name="sender">
        /// //
        /// </param>

        /// <param name="args">
        /// //
        /// </param>

        protected virtual void VolumePlus(object sender, EventArgs args)
        {
            _media.Volume += 0.1;
            _volumeSound.Volume += 0.1;

            _volumeSound.Stop();
            _volumeSound.Play();

            _volumePressed.Begin();
            _volumeSteps[Convert.ToInt32(_media.Volume * 10) - 1].Fill = _volumeColors[Convert.ToInt32(_media.Volume * 10) - 1];
        }

        /// <summary>
        /// //
        /// </summary>

        /// <param name="sender">
        /// //
        /// </param>

        /// <param name="args">
        /// //
        /// </param>

        protected virtual void VolumeMinus(object sender, EventArgs args)
        {
            _media.Volume -= 0.1;
            _volumeSound.Volume -= 0.1;

            _volumeSound.Stop();
            _volumeSound.Play();

            _volumePressed.Begin();
            _volumeSteps[Convert.ToInt32(_media.Volume * 10)].Fill = new SolidColorBrush(Color.FromRgb(33, 131, 197));
        }

        /// <summary>
        /// //
        /// </summary>

        /// <param name="sender">
        /// //
        /// </param>

        /// <param name="args">
        /// //
        /// </param>

        protected virtual void CheckState(object sender, EventArgs args)
        {
            if (_media.CurrentState == "Stopped")
            {
                _millisecond.Stop();
                _scrubTime.Text = "0:00 / " + _media.NaturalDuration.TimeSpan.Minutes + ":" + _media.NaturalDuration.TimeSpan.Seconds;

                _pause.Visibility = Visibility.Collapsed;
                _play.Visibility = Visibility.Visible;

                Scrub(0);
            }
        }

        /// <summary>
        /// //
        /// </summary>

        /// <param name="sender">
        /// //
        /// </param>

        /// <param name="args">
        /// //
        /// </param>

        protected virtual void CheckScrub(object sender, MouseEventArgs args)
        {
            if (_isScrubbing)
            {
                Scrub(args.GetPosition(_scrubRuler).X);
            }
        }

        /// <summary>
        /// //
        /// </summary>

        /// <param name="sender">
        /// //
        /// </param>

        /// <param name="args">
        /// //
        /// </param>

        protected virtual void ActivateScrubbing(object sender, MouseEventArgs args)
        {
            if (_pause.Visibility == Visibility.Visible)
            {
                _media.Pause();
                _millisecond.Stop();
            }

            _isScrubbing = true;

            CheckScrub(sender, args);
        }

        /// <summary>
        /// //
        /// </summary>

        /// <param name="sender">
        /// //
        /// </param>

        /// <param name="args">
        /// //
        /// </param>

        protected virtual void InactivateScrubbing(object sender, EventArgs args)
        {
            if (_pause.Visibility == Visibility.Visible)
            {
                _media.Play();
                _millisecond.Begin();
            }

            _isScrubbing = false;
        }

        /// <summary>
        /// //
        /// </summary>

        /// <param name="sender">
        /// //
        /// </param>

        /// <param name="args">
        /// //
        /// </param>

        protected virtual void MoveScrubber(object sender, EventArgs args)
        {
            _scrubber.SetValue(Canvas.LeftProperty, (Convert.ToDouble(_media.Position.TotalMilliseconds) / _milliseconds * _scrubRuler.Width) + 10);
            _scrubTime.Text = _media.Position.Minutes + ":" + _media.Position.Seconds + " / " + _media.NaturalDuration.TimeSpan.Minutes + ":" + _media.NaturalDuration.TimeSpan.Seconds;

            _millisecond.Begin();
        }

        /// <summary>
        /// //
        /// </summary>

        /// <param name="xCoordinate">
        /// //
        /// </param>

        protected virtual void Scrub(double xCoordinate)
        {
            if (xCoordinate < 0)
            {
                xCoordinate = 0;
            }

            else if (xCoordinate > _scrubRuler.Width)
            {
                xCoordinate = _scrubRuler.Width;
            }

            _scrubber.SetValue(Canvas.LeftProperty, xCoordinate + 10);
            _media.Position = new TimeSpan(0, 0, 0, 0, (int)(xCoordinate * _milliseconds / _scrubRuler.Width));
            _scrubTime.Text = _media.Position.Minutes + ":" + _media.Position.Seconds + " / " + _media.NaturalDuration.TimeSpan.Minutes + ":" + _media.NaturalDuration.TimeSpan.Seconds;
        }
    }
}
